﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Runtime.Serialization;
using System.ServiceModel;
using System.Text;
using Microsoft.SharePoint;
using CMISForSharePoint.cmisHelpers;
using CMISForSharePoint.cmisTypes;
using CMISForSharePoint.cmisEnums;
using CMISForSharePoint.Divers;
using System.Reflection;
using System.IO;
using CMISForSharePoint.cmisExceptions;


namespace CMISForSharePoint.CmisServices.RepositoryService
{



    public class CMISServices : IRepositoryService
    {

        #region IRepositoryService Members

        public cmisRepositoryEntryType[] GetRepositories()
        {



            using (SPHelper spHelper = new SPHelper())
            {

                List<SPDocumentLibrary> myDocList = spHelper.GetDocumentLibraries();
                List<cmisRepositoryEntryType> myRepositories = new List<cmisRepositoryEntryType>();
                //creating a cmisRepositoryEntryType for each document library
                foreach (SPDocumentLibrary myDocLib in myDocList)
                {
                    cmisRepositoryEntryType tmpRepository = new cmisRepositoryEntryType();
                    tmpRepository.repositoryID = myDocLib.ID.ToString();
                    tmpRepository.repositoryName = myDocLib.Title;
                    tmpRepository.repositoryURI = myDocLib.ParentWeb.Site.MakeFullUrl(myDocLib.RootFolder.Url);
                    myRepositories.Add(tmpRepository);
                }

                return myRepositories.ToArray();
            }
        }

        public cmisRepositoryInfoType getRepositoryInfo(string repositoryId)
        {

            using (SPHelper spHelper = new SPHelper())
            {
                Guid id = new Guid(repositoryId);

                //getting the repository by ID
                SPDocumentLibrary myDocLib = spHelper.GetDocumentLibrary(id);

                if (myDocLib != null)
                {
                    //creating a cmisRepositoryInfoType
                    cmisRepositoryInfoType myRepositoryInfo = new cmisRepositoryInfoType();
                    myRepositoryInfo.repositoryId = repositoryId;
                    myRepositoryInfo.repositoryName = myDocLib.Title;
                    myRepositoryInfo.repositoryRelationship = enumRepositoryRelationship.self.ToString();
                    myRepositoryInfo.repositoryDescription = myDocLib.Description;
                    myRepositoryInfo.vendorName = "ip-tech";
                    myRepositoryInfo.productName = "ip-tech CMIS4SharPoint";
                    myRepositoryInfo.productVersion = myDocLib.Version.ToString();
                    myRepositoryInfo.rootFolderId = myDocLib.RootFolder.UniqueId.ToString();

                    cmisRepositoryCapabilitiesType myRepositoryCap = new cmisRepositoryCapabilitiesType();
                    myRepositoryCap.capabilityMultifiling = true;
                    myRepositoryCap.capabilityUnfiling = true;
                    myRepositoryCap.capabilityVersionSpecificFiling = false;
                    myRepositoryCap.capabilityPWCUpdateable = true;
                    myRepositoryCap.capabilityAllVersionsSearchable = true;
                    myRepositoryCap.capabilityPWCSearchable = true;
                    myRepositoryCap.capabilityJoin = enumCapabilityJoin.inneronly;
                    myRepositoryCap.capabilityFullText = enumCapabilityFullText.fulltextandstructured;
                    myRepositoryCap.capabilityQuery = enumCapabilityQuery.both;

                    myRepositoryInfo.capabilities = myRepositoryCap;
                    myRepositoryInfo.cmisVersionsSupported = "0.5";
                    myRepositoryInfo.repositorySpecificInformation = null;

                    return myRepositoryInfo;

                }
            }

            return null;
        }

        public getTypesResponse getTypes(getTypes param)
        {

            using (SPHelper spHelper = new SPHelper())
            {
                SPDocumentLibrary myDocLib = spHelper.GetDocumentLibrary(new Guid(param.repositoryId));
                getTypesResponse response = new getTypesResponse();
                List<cmisTypeDefinitionType> myTypeList = new List<cmisTypeDefinitionType>();


                if (myDocLib != null)
                {

                    SPContentTypeCollection myContentTypesList = myDocLib.ContentTypes;

                    //we set the variable of the loop according to the function's parameter
                    #region Loop variable init
                    int start = 0;
                    int length = myContentTypesList.Count;

                    if (!String.IsNullOrEmpty(param.skipCount))
                    {
                        int.TryParse(param.skipCount, out start);
                        if (start < 0)
                        {
                            start = 0;
                        }
                    }
                    if (!String.IsNullOrEmpty(param.maxItems))
                    {
                        int.TryParse(param.maxItems, out length);
                        if (length > myContentTypesList.Count || length <= 0)
                        {
                            length = myContentTypesList.Count;
                        }
                        else
                        {
                            response.hasMoreItems = true;
                        }

                    }
                    #endregion
                    ////////////////////////////////////////////////////////////////////


                    for (int i = start; i < length; i++)
                    {
                        SPContentType myContentType = myContentTypesList[i];
                        if (String.IsNullOrEmpty(param.typeId) || param.typeId.Equals(myContentType.Id.ToString()))
                        {
                            //we create cmisTypeDefinitionTyp starting from the SPContentType using the SPhelper
                            cmisTypeDefinitionType myType = spHelper.SPContentTypeToCmisDefinitionType(myContentType);

                            //if this parameter is passed we return the PropertyDefinition
                            if (param.returnPropertyDefinitions.HasValue && param.returnPropertyDefinitions.Value)
                            {
                                List<cmisPropertyDefinitionType> myPropertyDefinitionList = new List<cmisPropertyDefinitionType>();
                                foreach (SPField field in myContentType.Fields)
                                {
                                    cmisPropertyDefinitionType myPropDefType = spHelper.SPFieldToCmisPropertyDefinitionType(field);
                                    if (myPropDefType != null)
                                    {
                                        myPropertyDefinitionList.Add(myPropDefType);
                                    }
                                }

                                myType.Items = myPropertyDefinitionList.ToArray();

                            }

                            myTypeList.Add(myType);
                        }
                    }




                    response.type = myTypeList.ToArray();
                }

                return response;


            }
        }

        public cmisTypeDefinitionType getTypeDefinition(string repositoryId, string typeId)
        {

            getTypes param = new getTypes();
            getTypesResponse response = new getTypesResponse();
            param.maxItems = "1";
            param.repositoryId = repositoryId;
            param.returnPropertyDefinitions = new System.Nullable<bool>(true);
            param.returnPropertyDefinitionsSpecified = true;
            param.skipCount = "0";
            param.typeId = typeId;

            //get typeDefinition is aspecial case of getTypes so we use it with the parameters specified above
            response = getTypes(param);

            if (response.type != null)
            {
                if (response.type.Length > 0)
                {
                    return response.type[0];
                }
            }
            return null;

        }

        #endregion

        //unused
        #region Utilities method
        //private void FillPropertyDefinition(cmisTypeDefinitionType myType, List<cmisPropertyDefinitionType> myPropertyDefinitionList)
        //{
        //    if (myPropertyDefinitionList.Count > 0)
        //    {
        //        myType.Items = new cmisPropertyDefinitionType[myPropertyDefinitionList.Count];
        //        int i = 0;
        //        foreach (cmisPropertyDefinitionType property in myPropertyDefinitionList)
        //        {
        //            switch (property.propertyType)
        //            {

        //                case enumPropertyType.boolean:
        //                    myType.Items[i] = property as cmisPropertyBooleanDefinitionType;
        //                    break;

        //                case enumPropertyType.id:
        //                    myType.Items[i] = property as cmisPropertyIdDefinitionType;
        //                    break;
        //                case enumPropertyType.integer:
        //                    myType.Items[i] = property as cmisPropertyIdDefinitionType;
        //                    break;
        //                case enumPropertyType.datetime:
        //                    myType.Items[i] = property as cmisPropertyDateTimeDefinitionType;
        //                    break;
        //                case enumPropertyType.@decimal:
        //                    myType.Items[i] = property as cmisPropertyDecimalDefinitionType;
        //                    break;
        //                case enumPropertyType.html:
        //                    myType.Items[i] = property as cmisPropertyHtmlDefinitionType;
        //                    break;
        //                case enumPropertyType.@string:
        //                    myType.Items[i] = property as cmisPropertyStringDefinitionType;
        //                    break;
        //                case enumPropertyType.uri:
        //                    myType.Items[i] = property as cmisPropertyUriDefinitionType;
        //                    break;
        //                case enumPropertyType.xml:
        //                    myType.Items[i] = property as cmisPropertyXmlDefinitionType;
        //                    break;

        //            }
        //            i++;

        //        }


        //    }
        //}
        #endregion

        #region INavigationService Members

        public getDescendantsResponse getDescendants(getDescendants param)
        {
            using (SPHelper spHelper = new SPHelper())
            {
                ////test
                //param.type = enumTypesOfFileableObjects.any;
                //param.folderId = "855e38f7-a639-45b3-bbea-c8a708915a2d";
                //param.repositoryId = "d63c9765-a108-43df-a3ba-4e355b8c4c5f";
                ////////param.orderByClause = "Name ASC";
                //param.filter = "Name,URI,ObjectId";
                ////////param.depth = "1";
                /////////////////////////////////

                getDescendantsResponse response = new getDescendantsResponse();
                //we create the root node
                response.@object = new cmisObjectType[1];
                SPFolder folder;

                SPDocumentLibrary myDocLib = spHelper.GetDocumentLibrary(new Guid(param.repositoryId));


                #region Testing passed parameters and Init
                if (param.folderId != myDocLib.RootFolder.UniqueId.ToString())
                {
                    SPListItem item = myDocLib.GetItemByUniqueId(new Guid(param.folderId));
                    folder = item.Folder;
                }
                else
                {
                    folder = myDocLib.RootFolder;
                }


                cmisObjectType obj = new cmisObjectType();
                int depth = 1;

                if (int.TryParse(param.depth, out depth))
                {
                    if (depth < 0)
                    {
                        depth = 10;
                    }
                }
                else
                {
                    depth = 1;
                }

                if (String.IsNullOrEmpty(param.filter))
                {
                    param.filter = "*";
                }
                string[] filter = CmisHelper.CmisFilterParser(param.filter);

                bool includeAllowableActions = false;
                if (param.includeAllowableActions.HasValue)
                {
                    includeAllowableActions = param.includeAllowableActions.Value;
                }

                enumRelationshipDirection includeRelationships = enumRelationshipDirection.none;
                if (param.includeRelationships.HasValue)
                {
                    includeRelationships = param.includeRelationships.Value;
                }
                
                #endregion

                //we call the SpHelper to constuct the folder's tree from SharePoint
                obj = spHelper.SPfolderTreeToCmisObjectType(obj, folder, depth, filter,
                                                            param.type, includeAllowableActions
                                                            , includeRelationships, param.orderByClause
                                                            );

                response.@object = obj.child;
                return response;

            }
        }

        public getChildrenResponse getChildren(getChildren param)
        {
            //test
            //param.type = enumTypesOfFileableObjects.documents;
            //param.folderId = "855e38f7-a639-45b3-bbea-c8a708915a2d";
            //param.repositoryId = "d63c9765-a108-43df-a3ba-4e355b8c4c5f";
            //param.orderByClause = "Name ASC";
            //param.filter = "Name,URI";

            /////////////////////////
            getChildrenResponse response = new getChildrenResponse();
            getDescendants descendantParam = new getDescendants();

            descendantParam.depth = "1";
            descendantParam.filter = param.filter;
            descendantParam.folderId = param.folderId;
            descendantParam.includeAllowableActions = param.includeAllowableActions;
            descendantParam.includeAllowableActionsSpecified = param.includeAllowableActionsSpecified;
            descendantParam.includeRelationships = param.includeRelationships;
            descendantParam.includeRelationshipsSpecified = param.includeRelationshipsSpecified;
            descendantParam.repositoryId = param.repositoryId;
            descendantParam.type = param.type;
            descendantParam.typeSpecified = param.typeSpecified;
            descendantParam.orderByClause = param.orderByClause;

            //getchildren is a special case of getDescendant so we use it
            getDescendantsResponse descendantResponse = getDescendants(descendantParam);

            response.@object = descendantResponse.@object;

            //we arrange the response accordiing to the maxItems and skipCount parameters if they were specified
            int maxItems = 0;
            int skipCount = 0;
            if (int.TryParse(param.skipCount, out skipCount) && skipCount > 0 && skipCount < response.@object.Count())
            {
                response.@object = response.@object.Skip(skipCount).ToArray();
            }

            response.hasMoreItems = false;
            if (int.TryParse(param.maxItems, out maxItems) && maxItems < response.@object.Count())
            {
                response.@object = response.@object.Take(maxItems).ToArray();
                response.hasMoreItems = true;

            }






            return response;
        }

        public getFolderParentResponse getFolderParent(getFolderParent param)
        {
            //test
            //param.folderId = "b07d1bf1-83e3-473a-a2c6-9ed588e5f419";
            //  // /*Root folder id*/ "855e38f7-a639-45b3-bbea-c8a708915a2d"

            //param.repositoryId = "d63c9765-a108-43df-a3ba-4e355b8c4c5f";
            //param.returnToRoot = true;
            //param.returnToRootSpecified = true;
            //param.filter = "Name";
            /////////////////////////
            
            using (SPHelper spHelper = new SPHelper())
            {

                getFolderParentResponse response = new getFolderParentResponse();
                SPFolder folder;
                List<cmisObjectType> path = new List<cmisObjectType>();

                SPDocumentLibrary myDocLib = spHelper.GetDocumentLibrary(new Guid(param.repositoryId));

                bool isRootFolder = (param.folderId == myDocLib.RootFolder.UniqueId.ToString());
                bool includeAllowableActions = param.includeAllowableActionsSpecified && param.includeAllowableActions.HasValue && param.includeAllowableActions.Value && !isRootFolder;
                bool includeRelationships = param.includeRelationshipsSpecified && param.includeRelationships.HasValue && param.includeRelationships.Value != enumRelationshipDirection.none;
                bool returnToRoot = param.returnToRootSpecified && param.returnToRoot.HasValue && param.returnToRoot.Value;


                #region Testing parameters and Init
                //Managing the repository's rootFolder 
                if (!isRootFolder)
                {
                    SPListItem item = myDocLib.GetItemByUniqueId(new Guid(param.folderId));

                    /*the function returns only the parentFolder  if returnToRoot==true else it returns all the path starting from the parameter's specified folder*/
                    if (returnToRoot)
                    {
                        folder = item.Folder;
                    }
                    else
                    {
                        folder = item.Folder.ParentFolder;
                    }


                }
                else
                {
                    folder = myDocLib.RootFolder;
                }

                //Managing the filter
                if (String.IsNullOrEmpty(param.filter))
                {
                    param.filter = "*";
                }
                else if (param.filter != "*")
                {
                    param.filter += ",ParentId";
                }
                string[] filter = CmisHelper.CmisFilterParser(param.filter);
                
                #endregion
                
                //getting the first parent
                cmisObjectType obj = spHelper.cmisFolderFactory(folder);
                
                
                //filtring properties
                obj.properties.Items = CmisHelper.CmisPropertyFilter(obj.properties.Items, filter);


                //setting the first parent allowable actions
                if (includeAllowableActions)
                {
                    obj.allowableActions = spHelper.cmisAllowableActionsFactory(folder.Item);
                }

                #region not suported :Relationship
                /*the relationship paradigim is not available in sharepoint*/
                //if ()
                //{
                //    obj.relationship =new cmisObjectType[]{ spHelper.cmisRelationshipFactory(folder.Item, param.includeRelationships.Value)};
                //}
                #endregion
               
                //ading the object to the path
                path.Add(obj);

                //Getting the path to the root folder
                #region return to root 
                if (returnToRoot)
                {

                    while (folder.UniqueId.ToString() != myDocLib.RootFolder.UniqueId.ToString())
                    {
                        folder = folder.ParentFolder;
                        obj = spHelper.cmisFolderFactory(folder);

                        //filtring properties
                        obj.properties.Items = CmisHelper.CmisPropertyFilter(obj.properties.Items, filter);

                        //setting the allowable actions
                        if (param.includeAllowableActionsSpecified && param.includeAllowableActions.HasValue && param.includeAllowableActions.Value && !isRootFolder)
                        {
                            obj.allowableActions = spHelper.cmisAllowableActionsFactory(folder.Item);
                        }

                        path.Add(obj);
                    }

                } 
                #endregion

                response.@object = path.ToArray();

                return response;

            }
        }

        public getObjectParentsResponse getObjectParents(getObjectParents param)
        {


            //test
            //param.objectId = "5607baf4-2972-4059-b381-ac4699506063";
            //  
            //
            //param.repositoryId = "d63c9765-a108-43df-a3ba-4e355b8c4c5f";
            //
            //param.filter = "Name";
            ///////////////////
          
            using (SPHelper spHelper = new SPHelper())
            {

                getObjectParentsResponse response = new getObjectParentsResponse();

                List<cmisObjectType> path = new List<cmisObjectType>();

                SPDocumentLibrary myDocLib = spHelper.GetDocumentLibrary(new Guid(param.repositoryId));
                SPListItem item = myDocLib.GetItemByUniqueId(new Guid(param.objectId));
                SPFile file;
                bool includeAllowableActions = param.includeAllowableActionsSpecified && param.includeAllowableActions.HasValue && param.includeAllowableActions.Value;
                bool includeRelationships = param.includeRelationshipsSpecified && param.includeRelationships.HasValue && param.includeRelationships.Value != enumRelationshipDirection.none;

                #region Manging Parameters and init
                if (item != null && item.File != null && item.File.ParentFolder != null)
                {
                    file = item.File;
                }
                else
                {
                    return response;
                }

                //managing the filter parameter
                if (String.IsNullOrEmpty(param.filter))
                {
                    param.filter = "*";
                }
                string[] filter = CmisHelper.CmisFilterParser(param.filter);

                //creating the object and applying the filter
                cmisObjectType obj = spHelper.cmisFolderFactory(file.ParentFolder);
                obj.properties.Items = CmisHelper.CmisPropertyFilter(obj.properties.Items, filter);


                //setting the parent allowable actions
                if (includeAllowableActions)
                {
                    obj.allowableActions = spHelper.cmisAllowableActionsFactory(file.ParentFolder.Item);
                }


                #region not suported :Relationship
                /*the relationship paradigim is not available in sharepoint*/
                //if ()
                //{
                //    obj.relationship =new cmisObjectType[]{ spHelper.cmisRelationshipFactory(file.ParentFolder.Item, param.includeRelationships.Value)};
                //}
                #endregion

                
                #endregion
                path.Add(obj);
                response.@object = path.ToArray();
                return response;

            }
        }

        public getCheckedoutDocsResponse getCheckedoutDocuments(getCheckedoutDocs param)
        {
            //TEST
            //param.folderID = "855e38f7-a639-45b3-bbea-c8a708915a2d";
            ////  /*folder id*/"e2cbf358-bb0b-431b-a789-f34603153200"
            ////
            //param.repositoryId = "d63c9765-a108-43df-a3ba-4e355b8c4c5f";
            ////////////////////////////////////////////////////////////////////////


            using (SPHelper spHelper = new SPHelper())
            {
                getCheckedoutDocsResponse response = new getCheckedoutDocsResponse();
                List<cmisObjectType> path = new List<cmisObjectType>();

                cmisObjectType obj;
                SPFile file;
                SPDocumentLibrary myDocLib = spHelper.GetDocumentLibrary(new Guid(param.repositoryId));


                int maxItems = 0;
                int skipCount = 0;
                bool includeAllowableActions = param.includeAllowableActionsSpecified && param.includeAllowableActions.HasValue && param.includeAllowableActions.Value;
                bool includeRelationships = param.includeRelationshipsSpecified && param.includeRelationships.HasValue && param.includeRelationships.Value != enumRelationshipDirection.none;

                //managing the filter parameter
                if (String.IsNullOrEmpty(param.filter))
                {
                    param.filter = "*";
                }
                string[] filter = CmisHelper.CmisFilterParser(param.filter);



                foreach (SPListItem item in myDocLib.Items)
                {
                    file = item.File;
                    if (file != null)
                    {

                        if (file.Level == SPFileLevel.Checkout)
                        {
                            //dealing with the folderId parameter
                            if (string.IsNullOrEmpty(param.folderID) || (param.folderID == file.ParentFolder.UniqueId.ToString()))
                            {
                                //creating the object and applying the filter
                                obj = spHelper.cmisDocumentFactory(file);
                                obj.properties.Items = CmisHelper.CmisPropertyFilter(obj.properties.Items, filter);

                                //setting allowable actions
                                if (includeAllowableActions)
                                {
                                    obj.allowableActions = spHelper.cmisAllowableActionsFactory(file.Item);
                                }


                                #region not suported :Relationship
                                /*the relationship paradigim is not available in sharepoint*/
                                //if ()
                                //{
                                //    obj.relationship =new cmisObjectType[]{ spHelper.cmisRelationshipFactory(file.Item, param.includeRelationships.Value)};
                                //}
                                #endregion



                                path.Add(obj);



                            }


                        }

                    }
                }

                //if skipCount is specified 
                if (int.TryParse(param.skipCount, out skipCount) && skipCount > 0 && skipCount < response.@object.Count())
                {
                    response.@object = response.@object.Skip(skipCount).ToArray();
                }


                response.hasMoreItems = false;
                //if maxItems is specified
                if (int.TryParse(param.maxItems, out maxItems) && maxItems < response.@object.Count())
                {
                    response.@object = response.@object.Take(maxItems).ToArray();
                    response.hasMoreItems = true;

                }


                response.@object = path.ToArray();
                return response;

            }
        }
        #endregion

        #region IObjectService Members

        //TEST
        private createDocument testCreateDocument()
        {
            createDocument response = new createDocument();
            response.folderId = "855e38f7-a639-45b3-bbea-c8a708915a2d";
            response.repositoryId = "d63c9765-a108-43df-a3ba-4e355b8c4c5f";

            response.versioningStateSpecified = true;
            response.versioningState = new System.Nullable<enumVersioningState>(enumVersioningState.checkedout);

            cmisContentStreamType content = new cmisContentStreamType();
            content.stream = File.ReadAllBytes(@"./testCmisCreatedocument.txt");

            content.filename = "testCmisCreatedocument.txt";
            content.length = content.stream.Length.ToString();
            response.properties = new cmisPropertiesType();


            response.properties.Items = new cmisProperty[1];

            response.contentStream = content;

            return response;




        }
        //////////////////////////////////////////

        /// <summary>
        /// 
        /// </summary>
        /// <param name="param"></param>
        /// <returns></returns>

        public createDocumentResponse createDocument(createDocument param)
        {

            using (SPHelper spHelper = new SPHelper())
            {
                //////TEST
                //param = testCreateDocument();

                //param.properties.Items[0] = spHelper.cmisPropertyStringFactory("Name", "Le nom du fichier a encore été modifié3", "11");
                //// ////////////////


                createDocumentResponse response = new createDocumentResponse();

                SPDocumentLibrary myDocLib = spHelper.GetDocumentLibrary(new Guid(param.repositoryId));
                SPFolder parentFolder;

                //managing the folderId parameter
                if (string.IsNullOrEmpty(param.folderId))
                {
                    parentFolder = myDocLib.RootFolder;
                }
                else
                {
                    parentFolder = myDocLib.ParentWeb.GetFolder(new Guid(param.folderId));
                }

                //the complete url of the documentLibrary+the file name with extension
                string url = myDocLib.ParentWeb.Url + "/" + parentFolder.Url + "/" + param.contentStream.filename;
                SPFile file = parentFolder.Files.Add(url, param.contentStream.stream, true);
                //to catch the exceptions of ignored properties
                try
                {
                    file = spHelper.SetCmisPropertyToSPfile(param.properties.Items, file);

                }
                catch (Exception ex)
                {


                }
                //we test the availabilty of the specified content type inside the library
                try
                {
                    SPContentTypeId contentTypeId = new SPContentTypeId(param.typeId);
                    if (myDocLib.ContentTypes[contentTypeId] == null)
                    {
                        throw new constraintViolationExceptionType(); ;
                    }
                }
                catch (Exception)
                {
                    throw new constraintViolationExceptionType();
                }



                //we set the publication state of the document if it's specified
                if (param.versioningStateSpecified)
                {
                    switch (param.versioningState.Value)
                    {
                        case enumVersioningState.checkedout:
                            {
                                if (file.Level != SPFileLevel.Checkout)
                                {
                                    file.CheckOut();
                                }
                                break;
                            }
                        case enumVersioningState.minor:
                            {

                                file.UndoCheckOut();
                                file.CheckIn("Checked-in via CMIS", SPCheckinType.MinorCheckIn);

                                break;
                            }
                        case enumVersioningState.major:
                            {

                                file.UndoCheckOut();
                                file.CheckIn("Checked-in via CMIS", SPCheckinType.MajorCheckIn);

                                break;
                            }
                        default:
                            break;
                    }

                }

                response.objectId = file.UniqueId.ToString();

                return response;

            }
        }
        public createFolderResponse createFolder(createFolder param)
        {
            //folder content type id="0x0120006B52E2B6AA3C7C4B89123A599EF95E21";

            using (SPHelper spHelper = new SPHelper())
            {
                createFolderResponse response = new createFolderResponse();
                SPDocumentLibrary myDocLib = spHelper.GetDocumentLibrary(new Guid(param.repositoryId));
                SPFolder parentFolder;
                
                //dealing with the case of the root folder
                if (param.folderId == myDocLib.RootFolder.UniqueId.ToString())
                {
                    parentFolder = myDocLib.RootFolder;
                }
                else
                {
                    parentFolder = myDocLib.ParentWeb.GetFolder(param.folderId);
                }

                SPFolder folder;
                //setting the url of the new folder
                string url = myDocLib.ParentWeb.Url + "/" + parentFolder.Url + "/" + "CMIS New folder";
                //getting the content type associated with the folder
                SPContentTypeId contentTypeId = new SPContentTypeId(param.typeId);
                
                //we verify that the content type code is correct
                if (spHelper.SPContentTypeToEnumCmisType(myDocLib.ContentTypes[contentTypeId]) == enumObjectType.folder)
                {
                    if (parentFolder != null)
                    {
                        folder = parentFolder.SubFolders.Add(url);
                    }
                    else
                    {
                        folder = myDocLib.RootFolder.SubFolders.Add(url);
                    }
                }
                else
                {
                    throw new constraintViolationExceptionType();
                }

                //we set the properties of the foldfer if available
                if (param.properties != null)
                {
                    folder = spHelper.SetCmisPropertyToSPfolder(param.properties.Items, folder);
                }
                response.objectId = folder.UniqueId.ToString();
                return response;
            }
        }
        
        
        public createRelationshipResponse createRelationship(createRelationship param)
        {
            throw new NotImplementedException("The relationship paradigm isn't supported in SharePoint");
        }
        public createPolicyResponse createPolicy(createPolicy param)
        {
            throw new NotImplementedException();
        }

        public getAllowableActionsResponse getAllowableActions(getAllowableActions param)
        {

            using (SPHelper spHelper = new SPHelper())
            {
                SPDocumentLibrary myDocLib = spHelper.GetDocumentLibrary(new Guid(param.repositoryId));
                getAllowableActionsResponse response = new getAllowableActionsResponse();
                SPListItem item;
                //dealing with the root folder case wich doesn't have allowable actions 
                //so we get it from it's child
                if (param.objectId == myDocLib.RootFolder.UniqueId.ToString())
                {

                    //the allowable actions are applied to a document library so we can use the root subfolder
                    if (myDocLib.RootFolder.SubFolders.Count > 0)
                    {
                        item = myDocLib.RootFolder.SubFolders[0].Item;

                    }
                    else if (myDocLib.RootFolder.Files.Count > 0)
                    {
                        item = myDocLib.RootFolder.Files[0].Item;
                    }
                    else
                    {
                        return response;
                    }



                }
                else
                {
                    item = myDocLib.GetItemByUniqueId(new Guid(param.objectId));

                }

                response.allowableActions = spHelper.cmisAllowableActionsFactory(item);

                return response;
            }


        }
      
        
        public getPropertiesResponse getProperties(getProperties param)
        {
            using (SPHelper spHelper = new SPHelper())
            {
                //TEST
                //param.objectId="ab9eb43a-9103-46b6-acb2-3bd4d92cc66d";
                //param.repositoryId = "d63c9765-a108-43df-a3ba-4e355b8c4c5f";

                /////////////////////////////////////////////////////

                SPDocumentLibrary myDocLib = spHelper.GetDocumentLibrary(new Guid(param.repositoryId));
                getPropertiesResponse response = new getPropertiesResponse();

                cmisObjectType obj = new cmisObjectType();
                SPListItem item = null;

                //creating the cmis object
                if (param.objectId == myDocLib.RootFolder.UniqueId.ToString())
                {
                    //creating the object in the case of the root folder
                    obj = spHelper.cmisFolderFactory(myDocLib.RootFolder);
                }
                else
                {
                    item = myDocLib.GetItemByUniqueId(new Guid(param.objectId));

                    switch (spHelper.SPContentTypeToEnumCmisType(item.ContentType))
                    {
                        case enumObjectType.document:
                            {
                                obj = spHelper.cmisDocumentFactory(item.File);
                                break;
                            }
                        case enumObjectType.folder:
                            {
                                obj = spHelper.cmisFolderFactory(item.Folder);
                                break;
                            }

                        default:
                            {
                                obj = spHelper.cmisObjectTypeFactory(item);
                                break;
                            }
                    }


                }



                //dealing with the filter
                if (String.IsNullOrEmpty(param.filter))
                {
                    param.filter = "*";
                }

                string[] filter = CmisHelper.CmisFilterParser(param.filter);
                if (filter != null)
                {
                    obj.properties.Items = CmisHelper.CmisPropertyFilter(obj.properties.Items, filter);
                }

                //including the allowable actions if needed
                if (param.includeAllowableActions.HasValue && param.includeAllowableActions.Value)
                {
                    obj.allowableActions = spHelper.cmisAllowableActionsFactory(item);
                }

                #region not supported: Relationship
                //enumRelationshipDirection includeRelationships = enumRelationshipDirection.none;
                //if (param.includeRelationships.HasValue)
                //{
                //    obj.relationship=new cmisObjectType[1];
                //    obj.relationship[0]= spHelper.cmisRelationshipFactory(item, param.includeRelationships.Value);
                //}
                #endregion

                response.@object = obj;

                return response;

            }
        }
        public getContentStreamResponse getContentStream(getContentStream param)
        {

            using (SPHelper spHelper = new SPHelper())
            {

                SPDocumentLibrary myDocLib = spHelper.GetDocumentLibrary(new Guid(param.repositoryId));
                getContentStreamResponse response = new getContentStreamResponse();
                cmisContentStreamType contentStream = new cmisContentStreamType();
                SPFile file = myDocLib.ParentWeb.GetFile(new Guid(param.documentId));

                contentStream.filename = file.Name;
                contentStream.length = file.Length.ToString();
                contentStream.mimeType = spHelper.MimeType(file.Name);
                contentStream.stream = file.OpenBinary();
                contentStream.uri = file.Url;

                response.contentStream = contentStream;

                return response;
            }


        }

        //Test
        private updateProperties testUpdateProperties()
        {
            SPHelper sphelper = new SPHelper();
            updateProperties param = new updateProperties();

            param.repositoryId = "d63c9765-a108-43df-a3ba-4e355b8c4c5f";
            param.objectId = "ab9eb43a-9103-46b6-acb2-3bd4d92cc66d";
            param.properties = new cmisPropertiesType();
            param.properties.Items = new cmisProperty[2];

            param.properties.Items[0] = sphelper.cmisPropertyStringFactory("Name", "New Document", "0");
            GC.Collect();
            return param;

        }
        ///////////////////////////////////////
        /// <summary>
        /// 
        /// </summary>
        /// <param name="param"></param>
        /// <returns></returns>

        public updatePropertiesResponse updateProperties(updateProperties param)
        {
            using (SPHelper spHelper = new SPHelper())
            {
                //TEST
                //param = testUpdateProperties();
                ///////////////////

                SPDocumentLibrary myDocLib = spHelper.GetDocumentLibrary(new Guid(param.repositoryId));
                updatePropertiesResponse response = new updatePropertiesResponse();
                SPListItem item = null;
                SPFolder folder;
                SPFile file;
                if (param.objectId == myDocLib.RootFolder.UniqueId.ToString())
                {
                    folder = spHelper.SetCmisPropertyToSPfolder(param.properties.Items, myDocLib.RootFolder);
                    response.objectId = folder.UniqueId.ToString();
                }
                else
                {
                    item = myDocLib.GetItemByUniqueId(new Guid(param.objectId));
                    if (item.File != null)
                    {
                        file = item.File;
                        if (file.Level != SPFileLevel.Checkout)
                        {
                            file.CheckOut();
                        }

                        file = spHelper.SetCmisPropertyToSPfile(param.properties.Items, file);
                        file.CheckIn("CMIS properties modification");
                        response.objectId = file.UniqueId.ToString();
                    }
                    else
                    {
                        folder = item.Folder;
                        folder = spHelper.SetCmisPropertyToSPfolder(param.properties.Items, folder);
                        response.objectId = folder.UniqueId.ToString();


                    }
                }

                return response;

            }

        }


        public moveObjectResponse moveObject(moveObject param)
        {
            using (SPHelper spHelper = new SPHelper())
            {
                //TEST
                //param.targetFolderId = "144e95c5-27ed-4342-b582-7026ef1996b4 ";
                //param.targetFolderId = myDocLib.RootFolder.UniqueId.ToString();//reverse move
                //param.repositoryId = "d63c9765-a108-43df-a3ba-4e355b8c4c5f";
                //param.objectId = "ab9eb43a-9103-46b6-acb2-3bd4d92cc66d";//object=fichier
                //param.objectId = "ef2ad096-6eca-44e7-8bf6-f1653b8b4ff3";//object=folder
                ////////////////////////////////////////////////////////////
                moveObjectResponse response = new moveObjectResponse();
                SPDocumentLibrary myDocLib = spHelper.GetDocumentLibrary(new Guid(param.repositoryId));
                SPListItem item;
                SPFile file;
                SPFolder folder;
                SPFolder targetFolder;


                if (param.objectId == myDocLib.RootFolder.UniqueId.ToString())
                {
                    //we can't move the root folder
                    throw new constraintViolationExceptionType();
                }
                else
                {
                    item = myDocLib.GetItemByUniqueId(new Guid(param.objectId));
                    targetFolder = myDocLib.ParentWeb.GetFolder(new Guid(param.targetFolderId));
                    if (targetFolder == null || item == null)
                    {
                        throw new invalidArgumentExceptionType();
                    }

                    string targetUrl = myDocLib.ParentWeb.Url + "/" + targetFolder.Url;
                    if (item.File != null)
                    {
                        file = item.File;
                        targetUrl += "/" + file.Name;
                        file.MoveTo(targetUrl, true);
                    }
                    else
                    {
                        folder = item.Folder;
                        targetUrl += "/" + folder.Name;
                        folder.MoveTo(targetUrl);

                    }

                }

                return response;


            }

        }

        public deleteObjectResponse deleteObject(deleteObject param)
        {

            using (SPHelper spHelper = new SPHelper())
            {
                //TEST
                //param.repositoryId = "d63c9765-a108-43df-a3ba-4e355b8c4c5f";
                //param.objectId = "ab9eb43a-9103-46b6-acb2-3bd4d92cc66d";//object=fichier
                //param.objectId = "ef2ad096-6eca-44e7-8bf6-f1653b8b4ff3";//object=folder
                ////////////////////////////////////////////////////////////
                deleteObjectResponse response = new deleteObjectResponse();
                SPDocumentLibrary myDocLib = spHelper.GetDocumentLibrary(new Guid(param.repositoryId));
                SPListItem item;
                SPFile file;
                SPFolder folder;



                if (param.objectId == myDocLib.RootFolder.UniqueId.ToString())
                {
                    //we can't delete the root folder
                    throw new operationNotSupportedExceptionType();
                }
                else
                {
                    item = myDocLib.GetItemByUniqueId(new Guid(param.objectId));
                    if (item == null)
                    {
                        throw new invalidArgumentExceptionType();
                    }

                    if (item.File != null)
                    {
                        file = item.File;

                        file.Delete();
                    }
                    else
                    {
                        folder = item.Folder;
                        if (folder.SubFolders.Count > 0 || folder.Files.Count > 0)
                        {
                            throw new constraintViolationExceptionType();
                        }
                        folder.Delete();

                    }

                }

                return response;

            }
        }

        public deleteTreeResponse deleteTree(deleteTree param)
        {

            //TEST

            //param.folderId = "d0bec6a7-0074-4db3-986e-5739d608f435";
            //param.repositoryId = "d63c9765-a108-43df-a3ba-4e355b8c4c5f";
            //param.unfileNonfolderObjects = enumUnfileNonfolderObjects.unfile;
            ///////////////////////////////////////////

            using (SPHelper spHelper = new SPHelper())
            {
                deleteTreeResponse response = new deleteTreeResponse();
                SPDocumentLibrary myDocLib = spHelper.GetDocumentLibrary(new Guid(param.repositoryId));
                SPListItem item;
                SPFolder folder;
                List<SPFile> unfilledFileCollection = new List<SPFile>();



                if (param.folderId == myDocLib.RootFolder.UniqueId.ToString())
                {
                    //we can't delete the root folder
                    throw new operationNotSupportedExceptionType();
                }
                else
                {
                    item = myDocLib.GetItemByUniqueId(new Guid(param.folderId));
                    if (item == null)
                    {
                        throw new invalidArgumentExceptionType();
                    }

                    if (item.File != null)
                    {
                        throw new invalidArgumentExceptionType();
                    }
                    else
                    {
                        folder = item.Folder;
                        switch (param.unfileNonfolderObjects)
                        {
                            case enumUnfileNonfolderObjects.unfile:
                                {
                                    string parentFolderUrl = myDocLib.ParentWeb.Url + "/" + folder.ParentFolder.Url;
                                    spHelper.GetFilesFromTree(folder, ref unfilledFileCollection);
                                    foreach (var file in unfilledFileCollection)
                                    {
                                        //moving all the files of the tree to the root folder
                                        file.MoveTo(parentFolderUrl + "/" + file.Name, true);
                                    }
                                    break;
                                }
                            case enumUnfileNonfolderObjects.deletesinglefiled:
                                break;
                            case enumUnfileNonfolderObjects.delete:
                                break;
                            default:
                                break;
                        }
                        folder.Delete();

                    }

                }

                return response;

            }
        }

        public setContentStreamResponse setContentStream(setContentStream param)
        {

            using (SPHelper spHelper = new SPHelper())
            {
                setContentStreamResponse response = new setContentStreamResponse();
                SPDocumentLibrary myDocLib = spHelper.GetDocumentLibrary(new Guid(param.repositoryId));
                SPFile file;

                file = myDocLib.ParentWeb.GetFile(new Guid(param.documentId));

                if (file != null)
                {
                    if (file.Level != SPFileLevel.Checkout)
                    {
                        file.CheckOut();
                    }
                    file.Item["Name"] = param.contentStream.filename;
                    file.Item.Update();
                    file.SaveBinary(param.contentStream.stream, false);

                    file.CheckIn("Content stream modified by CMIS");
                    file.Update();
                    response.documentId = file.UniqueId.ToString();
                }

                return response;

            }

        }

        public deleteContentStreamResponse deleteContentStream(deleteContentStream param)
        {
            using (SPHelper spHelper = new SPHelper())
            {
                //TEST
                //param.repositoryId = "d63c9765-a108-43df-a3ba-4e355b8c4c5f";
                //param.documentId = "d2381ffb-16b5-42d2-acea-7b5973a8119b";
                /////////////////////////////////////////////////

                deleteContentStreamResponse response = new deleteContentStreamResponse();
                SPDocumentLibrary myDocLib = spHelper.GetDocumentLibrary(new Guid(param.repositoryId));
                SPFile file;

                file = myDocLib.ParentWeb.GetFile(new Guid(param.documentId));

                if (file != null)
                {
                    if (file.Level != SPFileLevel.Checkout)
                    {
                        file.CheckOut();
                    }

                    file.SaveBinary(new byte[1] { 0 }, false);
                    file.CheckIn("Content stream deleted by CMIS");
                    file.Update();


                }

                return response;

            }
        }


        #endregion

        #region IVersioning Members
        public checkOutResponse checkOut(checkOut param)
        {
            using (SPHelper spHelper = new SPHelper())
            {
                checkOutResponse response = new checkOutResponse();
                SPDocumentLibrary myDocLib = spHelper.GetDocumentLibrary(new Guid(param.repositoryId));
                SPListItem item;
                SPFile file;

                item = myDocLib.GetItemByUniqueId(new Guid(param.documentId));

                if (item.File != null)
                {
                    file = item.File;
                    if (file.Level != SPFileLevel.Checkout)
                    {
                        file.CheckOut();
                        response.documentId = file.UniqueId.ToString();
                    }
                }
                else
                {
                    throw new constraintViolationExceptionType();
                }

                return response;

            }
        }
        public cancelCheckOutResponse cancelCheckOut(cancelCheckOut param)
        {
            using (SPHelper spHelper = new SPHelper())
            {
                cancelCheckOutResponse response = new cancelCheckOutResponse();
                SPDocumentLibrary myDocLib = spHelper.GetDocumentLibrary(new Guid(param.repositoryId));
                SPListItem item;
                SPFile file;

                item = myDocLib.GetItemByUniqueId(new Guid(param.documentId));

                if (item.File != null)
                {
                    file = item.File;
                    if (file.Level == SPFileLevel.Checkout)
                    {
                        file.UndoCheckOut();

                    }
                }
                else
                {
                    throw new constraintViolationExceptionType();
                }

                return response;

            }

        }
        public checkInResponse checkIn(checkIn param)
        {
            SPListItem item;
            SPFile file;
            checkInResponse response = new checkInResponse();


            try
            {
                using (SPHelper spHelper = new SPHelper())
                {
                    SPDocumentLibrary myDocLib = spHelper.GetDocumentLibrary(new Guid(param.repositoryId));


                    item = myDocLib.GetItemByUniqueId(new Guid(param.documentId));

                    if (item.File != null)
                    {
                        file = item.File;
                        response.documentId = file.UniqueId.ToString();
                        if (file.Level == SPFileLevel.Checkout)
                        {
                            if (param.properties != null)
                            {

                                updateProperties propertiesParam = new updateProperties();
                                propertiesParam.objectId = param.documentId;
                                propertiesParam.repositoryId = param.repositoryId;
                                propertiesParam.properties = param.properties;

                                updatePropertiesResponse responseProperties = updateProperties(propertiesParam);



                            }
                            if (param.contentStream != null)
                            {
                                setContentStream contentParam = new setContentStream();
                                contentParam.contentStream = param.contentStream;
                                contentParam.documentId = param.documentId;
                                contentParam.overwriteFlag = new Nullable<bool>(true);
                                contentParam.overwriteFlagSpecified = true;
                                contentParam.repositoryId = param.repositoryId;

                                setContentStreamResponse contentResponse = setContentStream(contentParam);


                            }

                        }
                    }

                }





                using (SPHelper spHelper = new SPHelper())
                {
                    SPDocumentLibrary myDocLib = spHelper.GetDocumentLibrary(new Guid(param.repositoryId));


                    item = myDocLib.GetItemByUniqueId(new Guid(param.documentId));
                    file = item.File;


                    if (param.major != null)
                    {
                        if (!String.IsNullOrEmpty(param.checkinComment) && param.major.Value)
                        {
                            file.CheckOut();
                            file.CheckIn(param.checkinComment, SPCheckinType.MajorCheckIn);
                        }
                        else
                        {
                            file.CheckOut();
                            file.CheckIn("Checked in with CMIS", SPCheckinType.MajorCheckIn);
                        }

                    }
                    else
                    {
                        if (!String.IsNullOrEmpty(param.checkinComment))
                        {
                            file.CheckOut();
                            file.CheckIn(param.checkinComment, SPCheckinType.MinorCheckIn);
                        }
                        else
                        {
                            file.CheckOut();
                            file.CheckIn("Checked in with CMIS", SPCheckinType.MinorCheckIn);
                        }
                    }

                }





                return response;

            }
            catch (Exception ex)
            {
                throw ex;
            }

        }
        public deleteAllVersionsResponse deleteAllVersions(deleteAllVersions param)
        {

            using (SPHelper spHelper = new SPHelper())
            {
                deleteAllVersionsResponse response = new deleteAllVersionsResponse();
                SPDocumentLibrary myDocLib = spHelper.GetDocumentLibrary(new Guid(param.repositoryId));
                SPListItem item;
                

                item=myDocLib.GetItemByUniqueId(new Guid(param.versionSeriesId));
                item.Delete();

                  
                return response;
            }
        }

        #endregion
    }
}
